# @Time : 2024/7/19 18:18
# @Author : Adam
# @Version : v1.0
# @IDE : PyCharm
# @Project : tracer

import random
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from django import forms

from web import models
from django.core.mail import send_mail
from django_redis import get_redis_connection
from utils.encrypt import md5
from web.forms.bootstrap import BootStrapForm


class RegisterModelForm(BootStrapForm, forms.ModelForm):
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'^(1[3-9])\d{9}$', '手机号格式错误'), ])
    password = forms.CharField(label='密码',
                               min_length=8,
                               max_length=64,
                               error_messages={
                                   'min_length': '密码长度不能小于8个字符',
                                   'max_length': '密码长度不能大于64个字符',
                               },
                               widget=forms.PasswordInput())
    confirm_password = forms.CharField(label='重复密码',
                                       min_length=8,
                                       max_length=64,
                                       error_messages={
                                           'min_length': '重复密码长度不能小于8个字符',
                                           'max_length': '重复密码长度不能大于64个字符',
                                       },
                                       widget=forms.PasswordInput())
    code = forms.CharField(label='验证码',
                           widget=forms.TextInput())

    class Meta:
        model = models.UserInfo
        fields = '__all__'

    def clean_username(self):
        username = self.cleaned_data['username']
        exists = models.UserInfo.objects.filter(username=username).exists()
        if exists:
            raise ValidationError('用户名已存在')
            # self.add_error('username','用户名已存在')
        return username

    def clean_email(self):
        email = self.cleaned_data['email']
        exists = models.UserInfo.objects.filter(email=email).exists()
        if exists:
            raise ValidationError('邮箱已存在')
        return email

    def clean_password(self):
        pwd = self.cleaned_data['password']
        # 加密 & 返回
        return md5(pwd)

    def clean_confirm_password(self):
        pwd = self.cleaned_data.get('password')
        confirm_pwd = md5(self.cleaned_data['confirm_password'])
        if pwd != confirm_pwd:
            raise ValidationError('两次密码不一致')
        return confirm_pwd

    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data['mobile_phone']
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if exists:
            raise ValidationError('手机号已注册')
        return mobile_phone

    def clean_code(self):
        code = self.cleaned_data['code']

        email = self.cleaned_data.get('email')
        if not email:
            return code

        conn = get_redis_connection()
        redis_code = conn.get(email)
        if not redis_code:
            raise ValidationError('验证码失效或未发送，请重新发送')
        redis_str_code = redis_code.decode('utf-8')

        if code.strip() != redis_str_code:
            raise ValidationError('验证码错误，请重新输入')
        return code


class SendEmailForm(forms.Form):
    email = forms.CharField(label='邮箱', validators=[
        RegexValidator(r'^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$', '邮箱格式错误'), ])

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_email(self):
        """邮箱校验的钩子"""
        email = self.cleaned_data['email']

        # 判断邮箱模板是否有问题
        tpl = self.request.GET.get('tpl')
        if tpl not in ['register', 'login']:
            raise ValidationError('邮箱模板错误')

        # 校验数据库中是否已经有邮箱
        exists = models.UserInfo.objects.filter(email=email).exists()
        if tpl == 'login':
            if not exists:
                raise ValidationError('邮箱不存在')
                # 发邮件 & 写 redis
            code = random.randrange(1000, 9999)
            result = send_mail('Tracer登录验证码', message=f'您的验证码是{code}', recipient_list=[email],
                               from_email=None)
        elif tpl == 'register':
            if exists:
                raise ValidationError('邮箱已存在')
                # 发邮件 & 写 redis
            code = random.randrange(1000, 9999)
            result = send_mail('Tracer注册验证码', message=f'您的验证码是{code}', recipient_list=[email],
                               from_email=None)

        if result != 1:
            raise ValidationError('邮件发送失败')

        # 验证码写入redis(django-redis)
        conn = get_redis_connection()
        conn.set(email, code, ex=60)
        #
        return email


class LoginEmailForm(BootStrapForm, forms.Form):
    email = forms.CharField(label='邮箱', validators=[
        RegexValidator(r'^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$', '邮箱格式错误'), ])
    code = forms.CharField(label='验证码',
                           widget=forms.TextInput())

    def clean_email(self):
        email = self.cleaned_data.get('email')
        user_object = models.UserInfo.objects.filter(email=email).first()
        if not user_object:
            raise ValidationError('邮箱不存在')
        return email

    def clean_code(self):
        code = self.cleaned_data.get('code')
        user_object = self.cleaned_data.get('email')
        # 邮箱不存在，则验证码无需校验
        if not user_object:
            return code

        conn = get_redis_connection()
        redis_code = conn.get(user_object.email)
        if not redis_code:
            raise ValidationError('验证码失效或未发送，请重新发送')

        redis_str_code = redis_code.decode('utf-8')

        if code.strip != redis_str_code:
            raise ValidationError('验证码错误，请重新输入')
        return code


class LoginForm(BootStrapForm, forms.Form):
    username = forms.CharField(label='邮箱或手机号')
    password = forms.CharField(label='密码', widget=forms.PasswordInput(render_value=True))
    code = forms.CharField(label='图片验证码')

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_password(self):
        pwd = self.cleaned_data.get('password')
        return md5(pwd)

    def clean_code(self):
        """钩子 图片验证码是否正确"""
        # 读取用户输入的验证码
        code = self.cleaned_data.get('code')
        # 去session中获取自己的验证码
        session_code = self.request.session.get('image_code')
        if not session_code:
            raise ValidationError('验证码失效或未发送，请重新发送')

        if code.strip().upper() != session_code.upper():
            raise ValidationError('验证码错误，请重新输入')
        return code
